﻿using System;
using RaisingStudio.Data.Common;
using RaisingStudio.Data.Expressions;
using System.Collections.Generic;
using System.Data;

namespace RaisingStudio.Data.Common
{
    public interface IDataContext
    {
        #region Properties
        /// <summary>
        /// Data Provider.
        /// </summary>
        IDataProvider Provider
        {
            get;
        }

        /// <summary>
        /// Database.
        /// </summary>
        ICommonDatabase Database
        {
            get;
        }
        #endregion

        #region Basic functions
        /// <summary>
        /// Get data count.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <returns>Data count.</returns>
        int GetCount<T>();
        /// <summary>
        /// Get data count.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condiion.</param>
        /// <returns>Data count.</returns>
        int GetCount<T>(ConditionExpression condition);

        /// <summary>
        /// Get Sum value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <returns>Sum value.</returns>
        object GetSum<T>(ColumnExpression column);
        /// <summary>
        /// Get Sum value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="condition">Condiion.</param>
        /// <returns>Sum value.</returns>
        object GetSum<T>(ColumnExpression column, ConditionExpression condition);

        /// <summary>
        /// Get Avg value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <returns>Avg value.</returns>
        object GetAvg<T>(ColumnExpression column);
        /// <summary>
        /// Get Avg value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="condition">Condiion.</param>
        /// <returns>Avg value.</returns>
        object GetAvg<T>(ColumnExpression column, ConditionExpression condition);
        /// <summary>
        /// Get Max value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <returns>Max value.</returns>
        object GetMax<T>(ColumnExpression column);
        /// <summary>
        /// Get Max value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="condition">Condiion.</param>
        /// <returns>Max value.</returns>
        object GetMax<T>(ColumnExpression column, ConditionExpression condition);
        /// <summary>
        /// Get Min value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <returns>Min value.</returns>
        object GetMin<T>(ColumnExpression column);
        /// <summary>
        /// Get Min value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="condition">Condiion.</param>
        /// <returns>Min value.</returns>
        object GetMin<T>(ColumnExpression column, ConditionExpression condition);
        #endregion

        #region ExecuteQuery
        /// <summary>
        /// Execute query command.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>Enumerator of given Type.</returns>
        IEnumerable<T> ExecuteQuery<T>(CommonCommand command);
        /// <summary>
        /// Execute query command.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>Enumerator of given Type.</returns>
        IEnumerable<T> ExecuteQuery<T>(CommonCommand command, int startRecord, int maxRecords);

        /// <summary>
        /// Execute query command for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>IList of given Type.</returns>
        List<T> ExecuteForList<T>(CommonCommand command);
        /// <summary>
        /// Execute query command for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>IList of given Type.</returns>
        List<T> ExecuteForList<T>(CommonCommand command, int startRecord, int maxRecords);

        /// <summary>
        /// Execute query command for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>DataTable.</returns>
        System.Data.DataTable ExecuteForDataTable<T>(CommonCommand command);
        /// <summary>
        /// Execute query command for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>DataTable.</returns>
        System.Data.DataTable ExecuteForDataTable<T>(CommonCommand command, int startRecord, int maxRecords);
        /// <summary>
        /// Execute query command for DataTable.
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>DataTable.</returns>
        System.Data.DataTable ExecuteForDataTable(CommonCommand command);
        /// <summary>
        /// Execute query command for DataTable.
        /// </summary>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>DataTable.</returns>
        System.Data.DataTable ExecuteForDataTable(CommonCommand command, int startRecord, int maxRecords);
        #endregion

        #region Query
        /// <summary>
        /// Query data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="columns">Columns.</param>
        /// <returns>Enumerator of given Type.</returns>
        IEnumerable<T> Query<T>(params ColumnExpression[] columns);
        /// <summary>
        /// Query data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Enumerator of given Type.</returns>
        IEnumerable<T> Query<T>(ConditionExpression condition, params ColumnExpression[] columns);
        /// <summary>
        /// Query data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="columns">Columns.</param>
        /// <returns>Enumerator of given Type.</returns>
        IEnumerable<T> Query<T>(ConditionExpression condition, int startRecord, int maxRecords, params ColumnExpression[] columns);

        /// <summary>
        /// Query data for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="columns">Columns.</param>
        /// <returns>IList of given Type.</returns>
        List<T> QueryForList<T>(params ColumnExpression[] columns);
        /// <summary>
        /// Query data for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>IList of given Type.</returns>
        List<T> QueryForList<T>(ConditionExpression condition, params ColumnExpression[] columns);
        /// <summary>
        /// Query data for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="columns">Columns.</param>
        /// <returns>IList of given Type.</returns>
        List<T> QueryForList<T>(ConditionExpression condition, int startRecord, int maxRecords, params ColumnExpression[] columns);

        /// <summary>
        /// Query data for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="columns">Columns.</param>
        /// <returns>DataTable.</returns>
        System.Data.DataTable QueryForDataTable<T>(params ColumnExpression[] columns);
        /// <summary>
        /// Query data for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>DataTable.</returns>
        System.Data.DataTable QueryForDataTable<T>(ConditionExpression condition, params ColumnExpression[] columns);
        /// <summary>
        /// Query data for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="columns">Columns.</param>
        /// <returns>DataTable.</returns>
        System.Data.DataTable QueryForDataTable<T>(ConditionExpression condition, int startRecord, int maxRecords, params ColumnExpression[] columns);
        #endregion

        #region Datatable
        /// <summary>
        /// Update DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataTable">DataTable.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        int UpdateDataTable<T>(System.Data.DataTable dataTable, params ColumnExpression[] columns);
        /// <summary>
        /// Create an empty DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="columns">Columns.</param>
        /// <returns>DataTable.</returns>
        System.Data.DataTable CreateDataTable<T>(params ColumnExpression[] columns);
  
        /// <summary>
        /// Fill DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataTable">DataTable.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully added to or refreshed. This does not include rows affected by statements that do not return rows. </returns>
        int FillDataTable<T>(System.Data.DataTable dataTable, params ColumnExpression[] columns);
        /// <summary>
        /// Fill DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataTable">DataTable.</param>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully added to or refreshed. This does not include rows affected by statements that do not return rows. </returns>
        int FillDataTable<T>(System.Data.DataTable dataTable, ConditionExpression condition, params ColumnExpression[] columns);
        /// <summary>
        /// Fill DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataTable">DataTable.</param>
        /// <param name="condition">Condition.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully added to or refreshed. This does not include rows affected by statements that do not return rows. </returns>
        int FillDataTable<T>(System.Data.DataTable dataTable, ConditionExpression condition, int startRecord, int maxRecords, params ColumnExpression[] columns);
        #endregion

        #region  Single entity
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Data.</returns>
        T GetData<T>(T dataObject, params ColumnExpression[] columns);
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKey">Primary key value.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Data.</returns>
        T GetData<T>(object primaryKey, params ColumnExpression[] columns);
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKeys">An array of primary key values.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Data.</returns>
        T GetData<T>(object[] primaryKeys, params ColumnExpression[] columns);
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Data.</returns>
        T GetData<T>(ConditionExpression condition, params ColumnExpression[] columns);
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>Data.</returns>
        T GetData<T>(CommonCommand command);

        /// <summary>
        /// Insert data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully inserted. </returns>
        int Insert<T>(T dataObject, params ColumnExpression[] columns);

        /// <summary>
        /// Update data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        int Update<T>(T dataObject, params ColumnExpression[] columns);
        /// <summary>
        /// Update data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKey">Primary key value.</param>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        int Update<T>(object primaryKey, T dataObject, params ColumnExpression[] columns);
        /// <summary>
        /// Update data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKeys">An array of primary key values.</param>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        int Update<T>(object[] primaryKeys, T dataObject, params ColumnExpression[] columns);

        /// <summary>
        /// Save data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        int Save<T>(T dataObject, params ColumnExpression[] columns);

        /// <summary>
        /// Delete data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <returns>The number of rows successfully deleted. </returns>
        int Delete<T>(T dataObject);
        /// <summary>
        /// Delete data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKeys">Primary key values.</param>
        /// <returns>The number of rows successfully deleted. </returns>
        int Delete<T>(params object[] primaryKeys);

        /// <summary>
        /// Check whether data exists or not.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <returns>If data exists return true, otherwise return false.</returns>
        bool Exists<T>(T dataObject);
        /// <summary>
        /// Check whether data exists or not.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKeys">Primary key values.</param>
        /// <returns>If data exists return true, otherwise return false.</returns>
        bool Exists<T>(params object[] primaryKeys);
        #endregion

        #region Batch operation
        /// <summary>
        /// Delete data according condition.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <returns>The number of rows successfully deleted. </returns>
        int Delete<T>(ConditionExpression condition);
        
        /// <summary>
        /// Check whether data exists or not, according condtion.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <returns>If data exists return true, otherwise return false.</returns>
        bool Exists<T>(ConditionExpression condition);

        /// <summary>
        /// Update data according condition.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        int Update<T>(T dataObject, ConditionExpression condition, params ColumnExpression[] columns);
        #endregion

        #region Database methods
        /// <summary>
        /// Executes the Command and builds an IDataReader. 
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>An IDataReader object. </returns>
        IDataReader ExecuteReader(CommonCommand command);
        /// <summary>
        /// Executes a Command and returns the number of rows affected. 
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>The number of rows affected. </returns>
        int ExecuteNoQuery(CommonCommand command);
        /// <summary>
        /// Executes the query, and returns the first column of the first row in the resultset returned by the query. Extra columns or rows are ignored. 
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>The first column of the first row in the resultset. </returns>
        object ExecuteScalar(CommonCommand command);

        /// <summary>
        /// Executes the Command and builds an IDataReader. 
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>An IDataReader object. </returns>
        IDataReader ExecuteReader<T>(CommonCommand command);
        /// <summary>
        /// Executes a Command and returns the number of rows affected. 
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>The number of rows affected. </returns>
        int ExecuteNoQuery<T>(CommonCommand command);
        /// <summary>
        /// Executes the query, and returns the first column of the first row in the resultset returned by the query. Extra columns or rows are ignored. 
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>The first column of the first row in the resultset. </returns>
        object ExecuteScalar<T>(CommonCommand command);
        #endregion
    }
}
